第一部分 预备知识
四类地址
- 虚拟地址(VA)
- 相对虚拟内存地址(RVA)
- 文件偏移地址(FOA)
- 特殊地址
虚拟地址:PE文件被加载到内存,PE对应的进程拥有了4GB的空间,这个空间存在的地址就是虚拟地址。
相对虚拟地址:相对与基地址的偏移量,RVA的存在是由于dll(模块)的基地址的不同而产生的。
文件偏移地址:文件中某个位置距离文件头的偏移量。
特殊位置,不细考究。
数据目录
数据目录记录的是整个PE结构中存在的数据类型。
节
节就是存放不同的类型的数据,不同的节区有不同的访问权限。
对齐
- 内存对齐
- 文件对齐
- 资源数据对齐
内存对齐:windows中,内存属性的基本单位是页,在32位系统是4KB(1000h),在64位系统中是8kb。
文件对齐:为了提高磁盘利用率,把一个物理扇区作为一个对齐粒度的大小,也就是12字节(200H),这是每个数据段都是200H的整数倍的原因。
第二部分 32位windows系统的PE结构
定位标准的PE头
由于DOS stub是一个不确定的长度,所以导致DOS头也是一个不确定的长度,这时候,我们采用e_lfanew字段来定位后续的PE结构位置。该字段是一个偏移量。PE头的定位遵循一下公式:PE_Start=DOS_MZ+IMAGE_HANDER.e_lfanew.
PE文件结构:
第三部分 PE文件头部解析
DOS MZ头
MZ头下有两个需要知道的成员。一个是e_magic ,一个是e_lfanew
PE头标志 Signature
Signature标志位于DOS_STUB之后,该标志位于e_lfanew所指向的位置。内容固定,对应的ASCII是”PE\0\0”。
标准PE头 IMAGE_FILE_HEADER
位置:在PE文件头标志的后面,位于e_lfanew+4的位置。
大小:占据了20个字节。
作用:他记录了PE文件的全局属性(运行的平台,PE文件的类型,文件中存在的节区总数)
以下是FILE_HEADER的成员信息:
- Machime:该文件的运行平台,是x86、x64还是I64等等,可以是下面值里的某一个。
- TimeDateStamp:PE文件的创建时间,一般有连接器填写
- NumberOfSections:该PE文件中有多少个节,也就是节表中的项数
- SizeOfOptionalHeader:紧随其后的可选头的大小。
拓展PE头IMAGE_OPTIONAL_HEADER32
|
|
需要我们熟悉的是以下几个成员。
- AddressOfEntryPoint; // 程序执行入口RVA
- BaseOfCode; // 代码的区块的起始RVA
- DWORD ImageBase; // 程序的首选装载地址
- SectionAlignment; // 内存中的区块的对齐大小
- FileAlignment; // 文件中的区块的对齐大小
- SizeOfImage; // 映像装入内存后的总尺寸
- DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 数据目录表
IMAGE_NT_HEADERS
包括三个部分组成:PE头标志,IMAGE_FILE_HEADER,IMAGE_OPTIOANAL_HEADER.
数据目录项 IMAGE_DATA_DIRECTORY
NT3.1开始,数据目录一共有16种,使用IMAGE_DATA_DIRECTORY来定义每种数据。
##节表项IMAGE_SECTION_HEADER
第三部分 详细解析PE文件头字段
IMAGE_FILE_HEADER字段
- Machine:
- 位置:+0004H,
- 大小:单字
- 作用:查看文件可以在那种机器上运行。
- NumberOfSection:
- 位置:+0006h
- 大小:单字
- 作用:文件中存在的节区的数目,数值不能小于1,但是节区数可以为0.
- TimeDateStamp
- 位置:+0008h
- 大小:双字
- 作用:编译时间,压缩时被修改。
- SizeofOptionalHeader
- 位置:+0014h
- 大小:单字
- 作用:指向的是OptionalHeader的大小。默认是00e0H,在64位是00f0H
- Character
- 位置:+0016h
- 大小:单字
- 作用:标志这PE文件的类型,如果这个值是010fh的话,表示这是一个EXE文件,如果值是210eh,表示这个值是DLL文件。
IMAGE_OPTIONAL_HEADER字段
- Magic:表示该文件的类型:如果是010Bh,表示文件是32位,如果是0107H,表示文件是ROM,如果是020BH,表示文件是64位PE
- AddressOfEntryPoint :表示启动代码距离PE加载后的初始位置的偏移量,如果病毒需要在程序中启动恶意代码,则需要修改这一成员的数值。但是对于DLL文件,这一成员你的数值为0,因为不存在入口点。
- BaseOfCode:代码段的起始RVA,但是不一定是程序的入口点。
- ImageBase:PE文件的加载基地址。exe文件通常是00400000.
- SizeOfImade:表示内存中整个PE文件的映射尺寸。
- DllCharacteristics:DLL文件属性,但是不单纯是针对DLL文件,对于所有PE文件同样有效。
- DataDirectory:目录数据,表示不同的节区的基本属性(RVA和size)。
IMAGE_SECTION_HEADER
- Name[IMAGE_SIZEOF_SHORT_NAME]: 八个字节的节去名称。
- VirtualAddress:节区的RVA
- SizeOfRAWDATA:节区对齐后的尺寸
- PointOfRAWDATA:节区数据在文件中的偏移量。
- PointerToRelocations:重定位表的指针
- NumberOfRelocations:重定位表的数目